package com.iplant.basic.filter;

import java.io.IOException;
import java.io.PrintWriter;
import java.util.Map;

import javax.annotation.PostConstruct;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.iplant.base.utils.general.Configuration;
import com.iplant.base.utils.sql.orm.ORMUtils;
import com.iplant.basic.serviceImpl.dao.bms.BMSEmployeeDAO;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.web.servlet.ServletComponentScan;
import org.springframework.stereotype.Component;

import com.alibaba.fastjson.JSON;
import com.iplant.base.controller.BaseController;
import com.iplant.base.po.ServiceResult;
import com.iplant.base.utils.RetCode;
import com.iplant.base.utils.SessionConstants;
import com.iplant.base.utils.general.DesUtil;
import com.iplant.base.utils.general.StringUtils;
import com.iplant.basic.service.BFCService;
import com.iplant.basic.service.BMSService;
import com.iplant.basic.service.po.bfc.BFCHomePageModule;
import com.iplant.basic.service.po.bms.BMSEmployee;

@Component
@ServletComponentScan
@WebFilter(urlPatterns = {"/api/*"}, filterName = "securityRequestFilter")
public class IsUserFilter implements Filter {
    private static final Logger logger = LoggerFactory.getLogger(IsUserFilter.class);

    private static final String NEED_TRACE_PATH_PREFIX = "/api/";

    private static IsUserFilter Instance;

    @Autowired
    BMSService wBMSService;
    @Autowired
    BFCService wBFCService;

    private static final String FILTER_APPLIED = "__spring_security_demoFilter_filterApplied";

    @PostConstruct
    public void init() {
        Instance = this;
        Instance.wBMSService = this.wBMSService;
        Instance.wBFCService = this.wBFCService;
        // 初使化时将已静态化的testService实例化

    }

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {

    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
            throws IOException, ServletException {
        String wURI = "";
        try {

            HttpServletResponse res = (HttpServletResponse) response;
            HttpServletRequest req = (HttpServletRequest) request;

            req.setCharacterEncoding("utf-8");

            wURI = req.getRequestURI();

            if (request.getAttribute(FILTER_APPLIED) != null) {
                if (chain != null)
                    chain.doFilter(request, response);
                return;
            }
            request.setAttribute(FILTER_APPLIED, true);

            if (!wURI.startsWith(BaseController.GetProjectName(req) + NEED_TRACE_PATH_PREFIX)) {
                if (chain != null) {
                    chain.doFilter(request, response);
                }
                return;
            }

            /*
              Session
             */
            BMSEmployee wBMSEmployee = BaseController.GetSession(req, BMSEmployee.class);
            boolean wNeedSetSession =
                    wBMSEmployee == null || (wBMSEmployee.ID <= 0 && wBMSEmployee.ID != BMSEmployee.SysAdmin.ID);

            boolean wHasCookies = false;

            try {

                /*
                  Cookie
                 */
                String user_info = BaseController.getCookieEnValue(SessionConstants.CookieUser, req);
                String wToken = res.getHeader(SessionConstants.TokenUser);

                if (StringUtils.isEmpty(user_info)) {
                    user_info = res.getHeader(SessionConstants.CookieUser);
                } else {
                    wHasCookies = true;
                }


                if (StringUtils.isNotEmpty(user_info)) {
                    /*
                      Cookie
                     */
                    if (wBMSEmployee == null || !user_info.equalsIgnoreCase(wBMSEmployee.getLoginName())) {
                        user_info = DesUtil.decrypt(user_info, SessionConstants.appSecret);
                        wToken = BaseController.CreateToken(user_info);
                        wBMSEmployee = Instance.wBMSService.BMS_LoginEmployeeByToken(user_info, wToken).getResult();
                    }
                } else if (StringUtils.isNotEmpty(wToken)) {
                    /*
                      Token
                     */
                    wBMSEmployee = Instance.wBMSService.BMS_LoginEmployeeByToken(user_info, wToken).getResult();

                } else if (req.getParameterMap() != null && req.getParameterMap().size() > 0) {
                    /*
                      Parameter 判断参数中是否有user字段
                     */
                    user_info = req.getParameter(SessionConstants.USER_INFO);
                    String user_password = req.getParameter(SessionConstants.USER_PASSWORD);

                    if (StringUtils.isNotEmpty(user_info) && StringUtils.isNotEmpty(user_password)) {
                        user_info = user_info.replaceAll(" ", "+");
                        user_password = user_password.replaceAll(" ", "+");

                        int wModuleID = StringUtils.parseInt(req.getParameter(SessionConstants.Extension_Module_ID));
                        if (wModuleID > 0) {
                            ServiceResult<BFCHomePageModule> wBFCHomePageModule = Instance.wBFCService
                                    .BFC_GetHomePageModuleByID(wBMSEmployee, wModuleID);
                            if (wBFCHomePageModule.getResult() != null
                                    && wBFCHomePageModule.getResult().getID() == wModuleID) {

                                user_info = DesUtil.decrypt(user_info, wBFCHomePageModule.getResult().getSecretKey());
                                user_password = DesUtil.decrypt(user_password,
                                        wBFCHomePageModule.getResult().getSecretKey());
                            }
                        } else {
                            user_info = DesUtil.decrypt(user_info, SessionConstants.appSecret);
                            user_password = DesUtil.decrypt(user_password, SessionConstants.appSecret);
                        }
                        wBMSEmployee = Instance.wBMSService.BMS_LoginEmployee(user_info, user_password, 0).getResult();
                    }
                }


            } catch (Exception e) {
                logger.error("Error Session: ", e);
            }

            // iframe引起的内部cookie丢失
            res.setHeader("P3P", "CP=CAO PSA OUR");
            res.setHeader("Access-Control-Allow-Origin", "*");
            res.setHeader("Access-Control-Allow-Credentials", "true");
            res.setHeader("Access-Control-Allow-Methods", "*");
            res.setHeader("Access-Control-Allow-Headers", "Content-Type,Access-Token,"
                    + SessionConstants.TokenUser + "," + SessionConstants.CookieUser);
            res.setHeader("Access-Control-Expose-Headers", "*");

            String wURL = req.getRequestURI();

            if (wBMSEmployee == null || (wBMSEmployee.ID <= 0 && wBMSEmployee.ID != BMSEmployee.SysAdmin.ID)) {

                if (!wURL.contains("User/Login") && !wURL.contains("HomePage/Index")
                        && !wURL.contains("RetrievePassword") && !wURL.contains("Logout")&& !wURL.contains("BFCAuthRecord")) {
                    returnJson(response, RetCode.SERVER_CODE_UNLOGIN, RetCode.SERVER_CODE_UNLOGIN_ALARM);
                    return;
                    // tip 未登录
                }
            } else if (wNeedSetSession) {
                if (wHasCookies) {
                    BaseController.SetSession(req, wBMSEmployee);
                    BaseController.SetCookie(req, res, wBMSEmployee);
                } else {
                    BaseController.SetSession(req, wBMSEmployee, 60);
                    BaseController.SetCookie(req, res, wBMSEmployee, 0);
                }
            }
            if (wURL.contains("User/Login")|| wURL.contains("BFCAuthRecord"))
            {
                if (chain != null) {
                    chain.doFilter(request, response);
                }
                return;
            }

            //剔除项目名称
            String wProjectName = BaseController.GetProjectName(req);
            if (wURI.startsWith(wProjectName)) {
                wURI = wURI.substring(wProjectName.length());
            }

            if (wBMSEmployee != null && wBMSEmployee.ID > 0) {
                String wDebuggerMode=StringUtils.parseString( req.getHeader("run-mode"));
                if(wDebuggerMode.equals("debugger"))
                {
                    if (chain != null) {
                        chain.doFilter(request, response);
                    }
                    return;
                }

                ServiceResult<Integer> wPowerServiceResult = Instance.wBMSService.BMS_CheckPower(wBMSEmployee,
                        wBMSEmployee.ID, wURI, 0, 0);

                if (wPowerServiceResult.Result != 1) {
                    if (wPowerServiceResult.Result == 2)

                        returnJson(response, RetCode.SERVER_CODE_ERR, RetCode.SERVER_CODE_UNROLE_Auth);
                    else
                        returnJson(response, RetCode.SERVER_CODE_ERR, RetCode.SERVER_CODE_UNROLE);

                    return;
                }
                Instance.wBMSService.BMS_UpdateLastOnlineTime(wBMSEmployee);
            }

            if (chain != null) {
                chain.doFilter(request, response);
            }
        } catch (Exception e) {
            logger.error("Error UserFilter: " + wURI, e);
        }
    }

    private void returnJson(ServletResponse response, int wErrorCode, String wMsg) {
        PrintWriter writer = null;
        response.setCharacterEncoding("UTF-8");
        response.setContentType("text/html; charset=utf-8");
        try {

            Map<String, Object> wResultMap = BaseController.GetResult(wErrorCode, wMsg);

            writer = response.getWriter();
            writer.print(StringUtils.toJSONString(wResultMap));

        } catch (IOException e) {
            logger.error("response error", e);
        } finally {
            if (writer != null)
                writer.close();
        }
    }

    @Override
    public void destroy() {

    }

}
